#![allow(dead_code)]
use std::cell::Cell;
use std::fmt;

#[derive(Debug)]
pub struct Person<'a> {
    pub name: &'a str,
    pub age: u32,
}

#[derive(Debug)]
pub struct Teacher {
    pub name: String,
    pub age: u32,
}

pub type Point = (u32, u32);

#[derive(Debug)]
pub struct MutPoint {
    pub x: i32,
    pub y: Cell<i32>,
}

#[test]
fn test_mutpoint() {
    let mp = MutPoint {
        x: 12,
        y: Cell::new(23),
    };
    mp.y.set(32);
    println!("mp =  {:?}", mp);
}

pub struct Structure(u32);

impl fmt::Display for Structure {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "{}", self.0)
    }
}

#[test]
fn test_structure() {
    let s = Structure(123);
    println!("s = {}", s);
}

pub struct List(Vec<u32>);

impl fmt::Display for List {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        let v = &self.0;

        write!(f, "[")?;

        for (count, item) in v.iter().enumerate() {
            if count != 0 {
                write!(f, ", ")?;
            }
            write!(f, "{}", item)?;
        }
        write!(f, "]")
    }
}

#[test]
fn test_list() {
    let l = List(vec![1, 2, 3, 4]);
    println!("l = {}", l);
}

struct RefBody<'a> {
    // 如果 struct 的成员是个引用，需要指明它的声明周期
    loc: &'a u32,
}

struct Adder {
    a: i32,
}

impl Adder {
    pub fn show(&self) {
        println!("adder.inner is {:?}", self.a);
        // self.add_one();
    }

    pub fn add_one(&mut self) {
        self.a += 1
    }

    pub fn add_two(&mut self) {
        self.add_one();
        self.add_one();
        self.show();
    }
}

#[test]
fn test_adder() {
    let mut adder = Adder { a: 0 };
    adder.show();
    adder.add_two();
}

enum SpecialPoint {
    Point(i32, i32),
    Special(String),
}

#[test]
fn enum_test() {
    let sp = SpecialPoint::Point(1, 2);
    match sp {
        SpecialPoint::Point(x, y) => println!("x = {:?}, y = {:?}", x, y),
        SpecialPoint::Special(why) => println!("I'm special, for {:?}", why),
    }
}

#[test]
fn tuple_test() {
    let tuple = (1, String::from("hello"));

    let (x, s) = tuple;
    // s 在上面被 move 了，tuple 不能再使用
    // println!("Tuple is: {:?}", tuple);
    println!("x = {:?}, s = {:?}", x, s);

    let tuple2 = (2, String::from("world"));
    // 这里忽略了 String，所以 tuple2 可以再使用
    let (y, _) = tuple2;
    println!("tuple is {:?}", tuple2);
    println!("y {:?}", y);
}

#[cfg(test)]
mod tests {
    use super::*;

    #[test]
    fn print_person() {
        let p = Person {
            name: "zs",
            age: 10,
        };
        println!("p = {:?}", p);
    }

    #[test]
    fn test_teacher() {
        let t = Teacher {
            name: String::from("hai"),
            age: 50,
        };

        println!("t = {:?}", t);
        let n = t.name;
        println!("n = {:?}", n);
        // can't compile
        // println!("t = {:?}", t);
    }
}
